package jhu.profiteer;

import java.io.IOException;
import jhu.profiteer.data.*;
import jhu.profiteer.data.Account;
import jhu.profiteer.data.AccountJpaController;
import jhu.profiteer.data.GameConfigurationParametersJpaController;

import jhu.profiteer.data.exceptions.NonexistentEntityException;
import java.util.Vector;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import jhu.profiteer.data.CharacterJpaController;

/**
 * Servlet implementation class Character
 */
public class Travel extends HttpServlet {

    /**
     * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        HttpSession session = request.getSession();
        Vector<String> notices = (Vector<String>) session.getAttribute("notices");
        boolean characterFound = true;
        String url = "";

        if (null == notices) {
            notices = new Vector<String>();
            session.setAttribute("notices", notices);
        }



        //check for a session attribute named �character� of type Character.
        jhu.profiteer.data.Character character = (jhu.profiteer.data.Character) session.getAttribute("character");
        // the servlet checks for a session attribute named �account�  of type Account
        Account account = (Account) session.getAttribute("account");

        if (null == character) {


            if (null == account) {
                this.getServletContext().getRequestDispatcher("/index").forward(request, response);
                return;
            }

            //search the database for a Character with an accountId equal to the value of the id field in the Account object.
            CharacterJpaController cjc = new CharacterJpaController();
            if (!cjc.testForCharacterWithAccountId(Long.parseLong(account.getId().toString()))) {
                character = null;
            } else {
                character = cjc.findCharacter(Long.parseLong(account.getId().toString()));
            }

            if (null == character) {
                //If no Character object is found in the database, redirect the user to the CharacterInformation page.
                this.getServletContext().getRequestDispatcher("/characterInformation").forward(request, response);
                return;

            }

        }
        //Once the Character object is found (either in the session or the database)
        if (null != character) {
            //check for a request parameter named locationId.
            String locationId = (String) request.getParameter("locationId");




            if ((null == locationId) || locationId.isEmpty() || !isLong(locationId)) {
                //redirect the user to the Map page with an error message “No location chosen.”

                notices.add("No location chosen.");
                this.getServletContext().getRequestDispatcher("/map").forward(request, response);
                return;

            } else {
                //search the database for a Location object with an id equal to the value of the locationId request parameter.
                LocationJpaController ljc = new LocationJpaController();

                Location destinationLocation = ljc.findLocation(Long.parseLong(locationId));




                //If no destination Location object is found in the database
                if (null == destinationLocation) {
                    //redirect the user to the Map page with an error message “No location chosen.”
                    if (null == notices) {
                        notices = new Vector<String>();
                    }

                    notices.add("No location chosen.");
                    this.getServletContext().getRequestDispatcher("/map").forward(request, response);
                    return;
                }
                //search the database for another Location object with an id equal to the value of the currentLocationId field in the Character object.
                ljc = new LocationJpaController();
                Location currentLocation = ljc.findLocation(character.getCurrentLocationId());



                //If no current Location object is found
                if (null == currentLocation) {
                    //the application has encountered an unrecoverable error.
                    if (null == account) {
                        this.getServletContext().getRequestDispatcher("/logout").forward(request, response);
                        return;
                    }
                    /* If an Account object is found,
                     * set the damaged field in the Account object to true, 
                     * create a database transaction, save the Account object to the database, 
                     * commit the transaction, 
                     * and redirect the user to the LogOut servlet with an error message
                     */
                    account.setDamaged(true);
                    AccountJpaController accjc = new AccountJpaController();

                    try {
                        accjc.edit(account);
                    } catch (NonexistentEntityException nee) {
                        nee.printStackTrace();
                        notices.add("No account exists.");
                    } catch (Exception e) {
                        e.printStackTrace();
                        notices.add("Error editing account.");
                    }

                    if (null == notices) {
                        notices = new Vector<String>();
                    }

                    notices.add("This account has been damaged and needs to be reviewed by a game administrator. An administrator will contact you once the account has been examined and a solution has been implemented.");
                    this.getServletContext().getRequestDispatcher("/logout").forward(request, response);
                    return;
                }
                //After both locations have been found
                if (currentLocation.canTravel(character, destinationLocation)) {
                    destinationLocation.generateCurrentValues(character);
                    character.setCurrentLocationId(destinationLocation.getId());
                    Long fuelCost = currentLocation.fuelCost(destinationLocation);

                    AirplaneJpaController ajc = new AirplaneJpaController();
                    Airplane airplane = (Airplane) session.getAttribute("airplane");
                    if (null == airplane) {
                        if (ajc.testForAirplaneWithCharacterId(character.getId())) {
                            airplane = ajc.findAirplaneByCharacterId(character.getId());
                        } else {
                            notices.add("This account has been damaged and needs to be reviewed by a game administrator. An administrator will contact you once the account has been examined and a solution has been implemented.");

                            this.getServletContext().getRequestDispatcher("/logout").forward(request, response);
                            return;

                        }

                    }
                    int newFuel = airplane.getCurrentFuel().intValue() - fuelCost.intValue();
                    airplane.setCurrentFuel(new Long(newFuel));
                    ajc = new AirplaneJpaController();

                    CharacterJpaController cjc = new CharacterJpaController();

                    try {
                        cjc.edit(character);
                        ajc.edit(airplane);
                    } catch (NonexistentEntityException nee) {
                        nee.printStackTrace();
                        notices.add("No entity exists.");
                    } catch (Exception e) {
                        e.printStackTrace();
                        notices.add("Error editing entity.");
                    }
                    if (null == notices) {
                        notices = new Vector<String>();
                    }


                    this.getServletContext().getRequestDispatcher("/market").forward(request, response);
                    return;

                } else {
                    if (null == notices) {
                        notices = new Vector<String>();
                    }

                    notices.add("You do not have enough fuel to travel to " + destinationLocation.getName() + ".");
                    this.getServletContext().getRequestDispatcher("/map").forward(request, response);
                    return;
                }
            }
        }

    }

    public boolean isLong(String s) {
        try {
            Long.parseLong(s);
        } catch (NumberFormatException nfe) {
            return false;
        }
        return true;
    }
    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">

    /**
     * Handles the HTTP <code>GET</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP <code>POST</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet.
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>
}
